package ace.cmp.spring.data.jdbc.querydsl.core.repository.handler.impl;

import ace.cmp.spring.data.jdbc.querydsl.core.model.PropertyRelation;
import ace.cmp.spring.data.jdbc.querydsl.core.repository.handler.QuerydslCreatedDateAnnotationHandler;
import ace.cmp.spring.data.jdbc.querydsl.core.repository.handler.QuerydslNowGenerator;
import ace.cmp.spring.data.jdbc.querydsl.core.util.QuerydslPropertyRelationUtils;
import com.querydsl.core.types.Path;
import com.querydsl.sql.dml.SQLInsertClause;
import com.querydsl.sql.dml.SQLUpdateClause;
import java.util.List;
import java.util.stream.Collectors;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.util.Assert;

/**
 * @author caspar
 * @date 2024/6/26 16:03 创建时间注解处理器，用于底层插入数据的时候自动处理字段时间
 */
public class QuerydslCreatedDateAnnotationHandlerImpl
    implements QuerydslCreatedDateAnnotationHandler {
  private final QuerydslNowGenerator querydslNowGenerator;
  private final QuerydslPropertyRelationUtils querydslPropertyRelationUtils;

  public QuerydslCreatedDateAnnotationHandlerImpl(
      QuerydslNowGenerator querydslNowGenerator,
      QuerydslPropertyRelationUtils querydslPropertyRelationUtils) {
    this.querydslPropertyRelationUtils = querydslPropertyRelationUtils;
    this.querydslNowGenerator = querydslNowGenerator;
  }

  @Override
  public void processInsert(
      Object entity, SQLInsertClause sqlClause, boolean enableCreatedDateForce) {
    List<PropertyRelation> propertyRelationList = this.getPropertyRelationList(entity);
    if (CollectionUtils.isEmpty(propertyRelationList)) {
      return;
    }
    for (PropertyRelation propertyRelation : propertyRelationList) {
      Object submitValue = querydslPropertyRelationUtils.getValue(entity, propertyRelation);
      Object generateValue = querydslNowGenerator.generate(propertyRelation);
      Assert.notNull(
          generateValue,
          String.format(
              "created date the type is not support,entity : %s, field name : %s",
              entity.getClass().getTypeName(), propertyRelation.getField().getName()));
      Object value = submitValue;
      if (submitValue == null || enableCreatedDateForce) {
        value = generateValue;
      }
      querydslPropertyRelationUtils.setValue(entity, propertyRelation, value);
      sqlClause.set((Path) propertyRelation.getPath(), value);
    }
  }

  @Override
  public void processUpdate(
      Object entity, SQLUpdateClause sqlClause, boolean enableCreatedDateForce) {
    // 更新的时候,强制框架处理,则忽略创建时间
    if (enableCreatedDateForce) {
      return;
    }
    this.getPropertyRelationList(entity)
        .forEach(
            propertyRelation -> {
              Object submitValue = querydslPropertyRelationUtils.getValue(entity, propertyRelation);
              if (submitValue == null) {
                return;
              }
              sqlClause.set((Path) propertyRelation.getPath(), submitValue);
            });
  }

  private List<PropertyRelation> getPropertyRelationList(Object entity) {
    return this.querydslPropertyRelationUtils
        .getPropertyRelation(entity.getClass(), CreatedDate.class)
        .values()
        .stream()
        .collect(Collectors.toList());
  }
}
